package com.yc.thread.pro2_knn.group;

import com.yc.thread.pro1_matrix.group.GroupMultiplierTask;
import com.yc.thread.pro2_knn.bean.BankMarketing;
import com.yc.thread.pro2_knn.bean.Distance;
import com.yc.thread.pro2_knn.bean.Sample;

import javax.management.MXBean;
import java.util.*;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * knn算法的任务调度类
 *
 * @author zwei
 * @create 2024-07-19 19:24
 */
public class ParalleGroupKnnClassifier {
    private int k;      //knn的k 表示近邻几个
    private int numThreads;     //线程数
    private boolean parallelSort;   //排序是否并行
    private List<BankMarketing> dataSet;     //训练集39129条，拿一条测试数据和它计算距离

    public ParalleGroupKnnClassifier(int k, int numThreads, boolean parallelSort, List<BankMarketing> dataSet) {
        this.k = k;
        this.numThreads = numThreads;
        this.parallelSort = parallelSort;
        this.dataSet = dataSet;
    }

    public String classify(Sample example) {
        Distance[] distances = new Distance[dataSet.size()];
        //1.计算32个线程中每个线程的计算任务的startIndex endIndex
        int length = dataSet.size() / numThreads;
        int startIndex = 0;
        int endIndex = length;
        List<Thread> list = new ArrayList<>();
        //2.根据numThreads创建任务  并绑定到线程上
        for (int i = 0; i < numThreads; i++) {
            GroupDistanceTask groupDistanceTask = new GroupDistanceTask(distances, startIndex, endIndex, dataSet, example);
            Thread t = new Thread(groupDistanceTask);
            t.start();
            list.add(t);
            //executor.execute(groupDistanceTask);    //加入线程池之后如何让其停下来？

            //计算下一个下一个线程的范围
            startIndex = endIndex;
            endIndex = endIndex + length;
            if (i == numThreads - 2) {
                endIndex = dataSet.size();
            }
            System.out.println("第" + i + "个线程的范围" + startIndex + "-" + endIndex);
        }
        //3.调用每个线程join(),让主线程停下来，计算时间
        for (Thread t : list) {
            try {
                t.join();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        //4.排序距离
        if (parallelSort) {
            Arrays.parallelSort(distances);
        } else {
            Arrays.sort(distances);
        }
        //5.将前k个样本的  标签存到Map<string,integer> 标签名，次数
        Map<String, Integer> results = new HashMap<>();
        for (int i = 0; i < k; i++) {
            Sample sample1 = dataSet.get(distances[i].getIndex());
            //sample  getTag()->获取标签getDAta()
            String tag = sample1.getTag();
//            if (results.containsKey(tag)){
//                results.put(tag,results.get(tag)+1);
//            }else {
//                results.put(tag,1);
//            }
            results.merge(tag, 1, (a, b) -> a + b);
        }
        //6.取出map中次数最多的标签名返回
        //传统写法
//        int max=0;
//        String maxTag="";
//        Set<Map.Entry<String,Integer>>set=results.entrySet();
//        for(Map.Entry<String,Integer> entry:set){
//            String tag=entry.getKey();
//            int value=entry.getValue();
//            if (value> max){
//                maxTag=tag;
//            }
//        }
//        return maxTag;
        //Collections工具类  对集合进行排序，查找，最值。。。
        return Collections.max(results.entrySet(), Map.Entry.comparingByValue()).getKey();
    }
}
